﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.ServiceModel.Activation;
using System.Text;
using System.Threading.Tasks;
using YasharEl.Infrastructure.Core.ServiceModel;
using YasharEl.Infrastructure.Diagnostics.Logging;
using YasharEl.Infrastructure.ObjectFactory;
using YasharEl.Infrastructure.ObjectFactory.Adapters;
using YasharEl.Infrastructure.ObjectFactory.ServiceModel;
using YasharEl.Infrastructure.ProcessEngine.DomainModel;

namespace YasharEl.Infrastructure.ProcessEngine.ServiceModel.Services
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    [ModuleService(ProcessEngineConstants.BaseName)]
    public partial class ProcessExecutorService
    {
        #region ReadOnly Fields

        private readonly IDependencyResolver resolver;
        private readonly ILogger<ProcessExecutorService> logger;
        private readonly ITypeAdapter typeAdapter;
        private readonly IProcessProcessor processor;

        #endregion

        #region Constructors

        public ProcessExecutorService(
            IDependencyResolver resolver, 
            ILogger<ProcessExecutorService> logger,
            ITypeAdapter typeAdapter,
            IProcessProcessor processor)
        {
            Contract.Requires<ArgumentNullException>(resolver != null, "resolver could not be null.");
            Contract.Requires<ArgumentNullException>(logger != null, "logger could not be null.");
            Contract.Requires<ArgumentNullException>(typeAdapter != null, "typeAdapter could not be null.");
            Contract.Requires<ArgumentNullException>(processor != null, "processor could not be null.");

            this.resolver = resolver;
            this.logger = logger;
            this.typeAdapter = typeAdapter;
            this.processor = processor;
        }

        #endregion

        #region ProcessExecutorService Overrides

        public override StartProcessResponse StartProcess(StartProcessRequest request)
        {
            logger.Debug("Start process of definition {0} and application {1} requested...", request.ProcessDefinitionId, request.ApplicationId);

            StartProcessResponse response = new StartProcessResponse()
            {
            };

            Dictionary<string,object> inputs = new Dictionary<string,object>();

            if (request.Inputs != null && request.Inputs.Count > 0)
            {
                foreach (KeyValuePair<string,PropertyAssignmentDTO> assignment in request.Inputs)
                {
                    inputs.Add(assignment.Key, assignment.Value.ValueContainer.Value);
                }
            }

            IProcess startedProcess = processor.StartProcess(
                request.ApplicationId,
                1,
                request.ProcessDefinitionId,
                request.Owner,
                string.Empty,
                inputs
            );

            if (startedProcess != null)
            {
                response.StartedProcess = typeAdapter.Adapt<IProcess, ProcessDTO>(startedProcess);
            }

            logger.Debug("Starting process of definition {0} and application {1} completed...", request.ProcessDefinitionId, request.ApplicationId);

            return response;
        }

        public override CancelProcessResponse CancelProcess(CancelProcessRequest request)
        {
            logger.Debug("Cancel process {0} within application {1} requested...", request.WorkflowInstanceId, request.ApplicationId);

            CancelProcessResponse response = new CancelProcessResponse()
            {
            };

            IProcess cancelledProcess = processor.CancelProcess(
                request.ApplicationId,
                1, 
                request.WorkflowInstanceId, 
                request.CancellationReason);

            if (cancelledProcess != null)
            {
                response.CancelledProcess = typeAdapter.Adapt<IProcess, ProcessDTO>(cancelledProcess);
            }

            logger.Debug("Cancelling process {0} within application {1} completed...", request.WorkflowInstanceId, request.ApplicationId);

            return response;
        }

        #endregion
    }
}
